package org.shell;

import java.io.Console;
import java.io.File;
import java.net.MalformedURLException;
import java.util.Calendar;
import java.util.UnknownFormatConversionException;
import org.shell.commands.CommandBuilder;
import org.shell.commands.CommandBuilderImpl;
import org.shell.commands.CommandInvoker;
import org.shell.commands.CommandsHolder;
import org.shell.commands.InputCommand;
import org.shell.commands.ShellCommand;
import org.shell.commands.exceptions.CommandNotAvailableException;
import org.shell.loaders.JarLoader;
import org.shell.loaders.Loader;
import org.shell.loaders.exceptions.LoaderGeneralException;
import org.shell.utils.config.ConfigManager;

public class Shell implements Runnable {

    private static String defaultConfigPath = "config.xml";
    private static String defaultPS = "Shell>";
    private static Console console;
    private static CommandBuilder builder;
    private Thread thread;

    public Shell() {
        thread = new Thread(this);
        thread.start();
    }

    public static void main(String args[]) {
        try {
            console = System.console();
            if (console == null) {
                throw new Exception("Cant find any system console");
            } else {
                initializeShell(args);
                startConsole();
            }
        } catch (Exception e) {
            System.err.println("Exiting:" + e.getMessage());
            System.exit(1);
        }
    }

    private static void initializeShell(String args[]) throws LoaderGeneralException, MalformedURLException {
        builder = new CommandBuilderImpl();
        loadSystemJar(System.getProperty("java.class.path"));
        readConfig(args.length >= 1 && new File(args[0]).exists() ? args[0] : defaultConfigPath);
    }

    private static void startConsole() {
        new Shell();
    }

    private static void loadSystemJar(String jarPath) throws LoaderGeneralException, MalformedURLException {
        Loader jarLoader = new JarLoader();
        jarLoader.load(jarPath, Boolean.FALSE);
    }

    private static void readConfig(String configPath) {
        try {
            new ConfigLoader(configPath);
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
        }
    }

    private String getPS() {
        String ps = (String) ConfigManager.get("system.ps");
        if (ps == null) {
            ps = Shell.defaultPS;
        }
        return ps;
    }

    public static void handleInput(String input) {
        InputCommand cmd;
        Object response;
        if (!input.equals("")) {
            try {
                cmd = (InputCommand) builder.buildCommand(input);
                if (CommandsHolder.isCommandAvailable(cmd)) {
                    response = CommandInvoker.invoke((ShellCommand) CommandsHolder.getCommand(cmd), cmd.getParameters());
                    if (response != null) {
                        console.writer().println(response.toString());
                    }
                } else {
                    throw new CommandNotAvailableException(cmd.getCommandName());
                }
            } catch (Exception e) {
                System.err.println(e.getLocalizedMessage());
            }
        }
    }

    public void run() {
        while (true) {
            try {
                handleInput(console.readLine(getPS() + " ", Calendar.getInstance()));
            } catch (UnknownFormatConversionException e) {
                System.err.println("Wrong PS format: " + e.getLocalizedMessage());
                handleInput(console.readLine(defaultPS + " ", Calendar.getInstance()));
            }
        }
    }
}
